/** 基于阿里巴巴 FastJson库二次封装
 * by @author lms 2019.04.27
 * */

package ms.core.tool;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;

public class JsonTool {

	/**
	 * 创建 JSONObject 对象
	 * @return
	 */
	public static Object newJSONObject() {
		return (new JSONObject());
	}

	/**
	 * JavaBean、Map、或 JSON 字符串转 JSONObject
	 * @param obj JavaBean Map 或 JSON 字符串
	 * @return JSONObject 或  null
	 */
	public static JSONObject getJSONObject(Object obj){
		if (obj==null) return null;

		try{
			if (obj instanceof String) {
				if (StrTool.isBlank(obj.toString()))
					return null;

				return JSON.parseObject(obj.toString());
			}
			if (obj instanceof JSONObject)
				return (JSONObject)obj;

			return (JSONObject) JSONObject.toJSON(obj);
		}catch(Exception e){
			Log4j2Tool.error(JsonTool.class, "getJSONObject", e);
			return null;
		}
	}

	/**
	 * 获取一个JSON对象元素数量
	 * @param obj JavaBean Map 或 JSON 字符串
	 * @return
	 */
	public static int sizeOfObject(Object obj) {
		JSONObject json = getJSONObject(obj);
		if (json==null) return 0;

		return json.size();
	}

	/**
	 * 对象转JSON字符串
	 * @param obj JavaBean、Map、JSONObject 或 JSON字符串
	 * @param prettyFormat 是否格式化输出
	 * @return JSON字符串或 null
	 */
	public static String objectToJson(Object obj, boolean prettyFormat){
		JSONObject json = getJSONObject(obj);
		if (json==null) return null;

		if (prettyFormat)
			return JSONObject.toJSONString(obj, prettyFormat);

		return json.toString();
	}

	/**
	 * 对象转JSON字符串，无格式化输出
	 * @param obj JavaBean、Map、JSONObject 或 JSON字符串
	 * @return JSON字符串或 null
	 */
	public static String objectToJson(Object obj){
		return objectToJson(obj,false);
	}

	/**
	 * 判断指定的key是否在一个JSON对象(JavaBean、Map、JSONObject 或 JSON字符串)里
	 * @param obj JavaBean、Map、JSONObject 或 JSON字符串
	 * @param key
	 * @return
	 */
	public static boolean containsKey(Object obj, String key){
		JSONObject jo = getJSONObject(obj);
		if (jo==null) return false;

		return jo.containsKey(key);
	}

	/**
	 * JSONObject、JSON字符串、Map 转 JavaBean
	 * @param obj JSONObject、JSON字符串、Map
	 * @param cls JavaBean 类对象
	 * @return JavaBea
	 */
	public static <T> T objectToBean(Object obj, Class<T> cls){
		JSONObject jo = getJSONObject(obj);
		if (jo==null) return null;

		try{
			 return JSON.toJavaObject(jo, cls);
		}catch(Exception e){
			Log4j2Tool.error(JsonTool.class, "objectToBean:", e);
		}
		return null;
	}

	/**
	 * 两JSON(JavaBean、Map、JSONObject 或 JSON字符串) 合并
	 * @param a JavaBean、Map、JSONObject 或 JSON字符串
	 * @param b JavaBean、Map、JSONObject 或 JSON字符串
	 * @return JSONObject
	 */
	public static JSONObject objJoinObj(Object a, Object b){
		try{
			JSONObject aObj = getJSONObject(a);
			JSONObject bObj = getJSONObject(b);
			JSONObject ret = new JSONObject();
			ret.putAll(aObj);
			ret.putAll(bObj);
	        return ret;
		}catch(Exception e){
			Log4j2Tool.error(JsonTool.class, "objJoinObj:", e);
			return null;
		}
	}

	/**
	 * List<JavaBean>转JSON字符串
	 * @param list
	 * @param prettyFormat 格式化输出
	 * @return string
	 */
	public static String listBeanToJson(List<?> list, boolean prettyFormat){
		if (list==null) return null;

		try{
			return JSON.toJSONString(list, prettyFormat);
		}catch(Exception e){
			Log4j2Tool.error(JsonTool.class, "listBeanToJson:", e);
		}
		return null;
	}

	/**
	 * List<JavaBean>转JSON字符串
	 * @param list
	 * @return string
	 */
	public static String listBeanToJson(List<?> list){
		return listBeanToJson(list, false);
	}

	/**
	 * JSON字符串数组转List<JavaBean>
	 * @param json JSON字符串数组
	 * @param cls JavaBean类
	 * @return List<JavaBean>
	 */
	public static <T> List<T> jsonToListBean(Object json, Class<T> cls){
		if (json==null) return null;

		try{
			String array = null;
			if (json instanceof String) array = json.toString();
			else array = JSON.toJSONString(json);
			if (StrTool.isBlank(array)) return null;

			return JSON.parseArray(array, cls);
		}catch(Exception e){
			Log4j2Tool.error(JsonTool.class, "jsonToListBean:", e);
		}
		return null;
	}

	/**
	 * JSON(JavaBean、Map、JSONObject 或 JSON字符串) 添加节点，如果节点已存在，则覆盖
	 * @param obj JSONObject对象
	 * @param key 节点名称
	 * @param value 节点值
	 * @return
	 */
	public static JSONObject addNode(Object obj, String key, Object value){
		try{
			JSONObject ret = getJSONObject(obj);
			if (ret==null) ret = new JSONObject();
			ret.put(key, value);
			return ret;
		}catch(Exception e){
			Log4j2Tool.error(JsonTool.class, "addNode:", e);
		}
		return null;
	}

	/**
	 * 按key删除JSON(JavaBean、Map、JSONObject 或 JSON字符串)节点
	 *
	 * @param obj json string
	 * @param key key of json item
	 * @return
	 */
	public static JSONObject delNode(Object obj, String key){
		JSONObject ret = getJSONObject(obj);
		if (ret==null) return null;

		try{
			ret.remove(key);
			return ret;
		}catch(Exception e){
			Log4j2Tool.error(JsonTool.class, "delNode:", e);
		}
		return ret;
	}

	/**
	 * 从JSON(JavaBean、Map、JSONObject 或 JSON字符串)获取某Key的值
	 * @param obj JSON(JavaBean、Map、JSONObject 或 JSON字符串)
	 * @param key 主键
	 * @return key对应值 或 null
	 */
	public static Object getValue(Object obj, Object key){
		JSONObject ret = getJSONObject(obj);
		if (ret==null) return null;

		return ret.get(key);
	}

	/**
	 * 从JSON(JavaBean、Map、JSONObject 或 JSON字符串)获取某Key的值
	 * @param obj JSON(JavaBean、Map、JSONObject 或 JSON字符串)
	 * @param key 主键名称
	 * @param value 默认值
	 * @return key对应值 或 null
	 */
	public static Object getValue(Object obj, String key, Object value){
		Object ret = getValue(obj, key);
		if (ret==null) ret = value;

		return ret;
	}

	/**
	 * 从JSON(JavaBean、Map、JSONObject 或 JSON字符串)获取某Key的字符串值,如果key不存在，则返回默认值
	 * @param obj JSON(JavaBean、Map、JSONObject 或 JSON字符串)
	 * @param key 主键名称
	 * @param value 默认值
	 * @return
	 */
	public static String getStrValue(Object obj, String key, String value){
		Object o = getValue(obj, key, value);
		if (o==null && value==null) return value;

		return String.valueOf(o);
	}

	/**
	 * 从JSON(JavaBean、Map、JSONObject 或 JSON字符串)获取某Key的整型值,如果key不存在，则返回默认值
	 * @param obj JSON(JavaBean、Map、JSONObject 或 JSON字符串)
	 * @param key 关键字
	 * @param value 默认值
	 * @return
	 */
	public static Integer getIntValue(Object obj, String key, Integer value){
		Object o = getValue(obj, key, value);

		try {
			return Integer.valueOf(String.valueOf(o));
		}catch(Exception e) {
			Log4j2Tool.error(JsonTool.class, "getIntValue:", e);
		}
		return value;
	}

	/**
	 * 从JSON(JavaBean、Map、JSONObject 或 JSON字符串)获取某Key的long值,如果key不存在，则返回默认值
	 * @param obj JSON(JavaBean、Map、JSONObject 或 JSON字符串)
	 * @param key 主键
	 * @param value 默认值
	 * @return
	 */
	public static Long getLongValue(Object obj, String key, Long value){
		Object o = getValue(obj, key, value);

		try {
			return Long.valueOf(String.valueOf(o));
		}catch(Exception e) {
			Log4j2Tool.error(JsonTool.class, "getLongValue:", e);
		}
		return value;
	}

	/**
	 * 从JSON(JavaBean、Map、JSONObject 或 JSON字符串)获取某Key的float值,如果key不存在，则返回默认值
	 * @param obj JSON(JavaBean、Map、JSONObject 或 JSON字符串)
	 * @param key 主键
	 * @param value 默认值
	 * @return
	 */
	public static Float getFloatValue(Object obj, String key, Float value){
		Object o = getValue(obj, key, value);
		if (o==null)
			return value;

		String tmp = String.valueOf(o).trim();
		if (StrTool.isBlank(tmp) || "-".equals(tmp))
			return value;

		try {
			return Float.valueOf(tmp);
		}catch(Exception e) {
			Log4j2Tool.error(JsonTool.class, "getFloatValue:", e);
		}
		return value;
	}

	/**
	 * 从JSON(JavaBean、Map、JSONObject 或 JSON字符串)获取某Key的float值,如果key不存在，则返回默认值
	 * @param obj JSON(JavaBean、Map、JSONObject 或 JSON字符串)
	 * @param key 主键
	 * @param value 默认值
	 * @return
	 */
	public static Double getDoubleValue(Object obj, String key, Double value){
		Object o = getValue(obj, key, value);
		if (o==null)
			return value;

		String tmp = String.valueOf(o).trim();
		if (StrTool.isBlank(tmp) || "-".equals(tmp))
			return value;

		try {
			return Double.valueOf(tmp);
		}catch(Exception e) {
			Log4j2Tool.error(JsonTool.class, "getDoubleValue:", e);
		}
		return value;
	}

	/**
	 * 从JSON(JavaBean、Map、JSONObject 或 JSON字符串)获取某Key的日期值,如果key不存在，则返回默认值
	 * @param obj JSON(JavaBean、Map、JSONObject 或 JSON字符串)
	 * @param key 主键
	 * @param value 默认值
	 * @return
	 */
	public static Date getDateValue(Object obj, String key, Date value){
		Object o = getValue(obj, key);
		if (o==null) return value;
		if (o instanceof Date) return (Date) o;
		if (o instanceof Long) {
			long time = (long) o;
			Date date = DateTimeTool.unixTimeToDate(time);
			return DateTimeTool.truncateTime(date);
		}
		if (o instanceof String && StrTool.isBlank(o.toString()))
			return null;

		SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
		try{
			return format.parse(o.toString());
		}catch(ParseException e){
			Log4j2Tool.error(JsonTool.class, "getDateValue:", e);
		}
		return value;
	}

	/**
	 * 从JSON(JavaBean、Map、JSONObject 或 JSON字符串)获取某Key的时间日期值,如果key不存在，则返回默认值
	 * @param obj JSON(JavaBean、Map、JSONObject 或 JSON字符串)
	 * @param key 主键
	 * @param value 默认值
	 * @return
	 */
	public static Date getDatetimeValue(Object obj, String key, Date value){
		Object o = getValue(obj, key);
		if (o==null) return value;
		if (o instanceof Date) return (Date) o;
		if (o instanceof Long) {
			long time = (long) o;
			return DateTimeTool.unixTimeToDate(time);
		}

		String time = o.toString();
		if (time.indexOf(":")<0) time += " 00:00:00";
		if (time.length()==16) time += ":00";
		SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		try{
			return format.parse(time);
		}catch(ParseException e){
			Log4j2Tool.error(JsonTool.class, "getDatetimeValue:", e);
		}
		return value;
	}

	////////////////////////////////////////////// JSON Array ///////////////////////////////////////////////

	/**
	 * 创建 JSONArray 对象
	 * @return
	 */
	public static JSONArray newJSONArray() {
		return (new JSONArray());
	}

	/**
	 * JSON 字符串数组、List<JavaBean> 转JSONArray
	 * @param aryObject array 对象，如JSON字符串数组、JSONArray、List<Map>、List<JavaBean>
	 * @return
	 */
	public static JSONArray getJSONArray(Object aryObject){
		if (aryObject==null) return null;

		try{
			if (aryObject instanceof String)
				return JSON.parseArray((String) aryObject);

			if (aryObject instanceof JSONArray)
				return (JSONArray) aryObject;

			return JSON.parseArray(JSON.toJSONString(aryObject));
		}catch(Exception e){
			Log4j2Tool.error(JsonTool.class, "getJSONArray:", e);
			return null;
		}
	}

	/**
	 * 判断JSONArray对象大小
	 * @param aryObject JSONArray对象(JSON字符串数组、JSONArray、List<Map>、List<JavaBean>)数组大小
	 * @return -1 表示数组为空或无效数组
	 */
	public static int sizeOfArray(Object aryObject){
		JSONArray ary = getJSONArray(aryObject);
		if (ary==null) return -1;

		return ary.size();
	}

	/**
	 * JSON数组对象转JSON字符串
	 * @param obj List<JavaBean>、List<Map>、JSONArray 或 JSON字符串数组
	 * @param formated 是否格式化输出
	 * @return 格式化过的JSON字符串数组或 null
	 */
	public static String arrayToJson(Object obj, boolean formated){
		JSONArray json = getJSONArray(obj);
		if (json==null) return null;

		if (formated)
			return json.toString(SerializerFeature.PrettyFormat);

		return json.toString();
	}

	/**
	 * JSON数组对象转JSON字符串，无格式化输出
	 * @param obj List<JavaBean>、List<Map>、JSONArray 或 JSON字符串数组
	 * @return 未格式化的JSON字符串数组或 null
	 */
	public static String arrayToJson(Object obj){
		return arrayToJson(obj,false);
	}

	/**
	 * JSONArray数组合并
	 * @param aryObjectA JSON字符串数组、JSONArray、List<Map>、List<JavaBean>
	 * @param aryObjectB JSON字符串数组、JSONArray、List<Map>、List<JavaBean>
	 * @return
	 */
	public static JSONArray arrayJoinArray(Object aryObjectA, Object aryObjectB){
		JSONArray ret = new JSONArray();
		JSONArray objA = getJSONArray(aryObjectA);
		if (objA!=null) ret.addAll(objA);

		JSONArray objB = getJSONArray(aryObjectB);
		if (objB!=null) ret.addAll(objB);

		return ret;
	}

	/**
	 * 获取JSNOArray 某行的值
	 * @param aryObject JSON数组(JSON字符串数组、JSONArray、List<Map>、List<JavaBean>)
	 * @param row 行索引，0~(n-1)
	 * @return
	 */
	public static Object getArrayRow(Object aryObject, int row) {
		JSONArray ary = getJSONArray(aryObject);
		if (ary==null || row<0 || row>=ary.size()) return null;

		JSONObject obj = ary.getJSONObject(row);
		return obj;
	}

	/**
	 * 从JSON数组根据指定值，检索JSON行
	 * @param aryObject JSON数组(JSON字符串数组、JSONArray、List<Map>、List<JavaBean>)
	 * @param key 主键
	 * @param value 值
	 * @return
	 */
	public static Object getArrayRow(Object aryObject, String key, Object value){
		JSONArray ary = getJSONArray(aryObject);
		if (ary==null) return null;

		for (int i=0; i<ary.size(); i++){
			JSONObject obj = ary.getJSONObject(i);
			if (obj==null) continue;

			Object tmp = obj.get(key);
			if (tmp!=null && tmp.equals(value)) return obj;
		}
		return null;
	}

	/**
	 * 从JSON数组获取指定行某主键的值
	 * @param aryObject JSON数组(JSON字符串数组、JSONArray、List<Map>、List<JavaBean>)
	 * @param row 行索引，0~(n-1)
	 * @param key 主键
	 * @return null or object
	 */
	public static Object getArrayRowValue(Object aryObject, int row, Object key){
		Object obj = getArrayRow(aryObject, row);
		if (obj==null) return null;

		return getValue(obj, key);
	}

	/**
	 * 从JSON数组获取指定行某主键的值
	 * @param aryObject JSON数组(JSON字符串数组、JSONArray、List<Map>、List<JavaBean>)
	 * @param row 行索引，0~(n-1)
	 * @param key 主键
	 * @param value 默认值
	 * @return null or object
	 */
	public static Object getArrayRowValue(Object aryObject, int row, String key, Object value){
		Object ret = getArrayRowValue(aryObject, row, key);
		if (ret==null) ret = value;

		return ret;
	}

	/**
	 * 从JSON数组获取指定行某主键的字符串值
	 * @param aryObject JSON数组(JSON字符串数组、JSONArray、List<Map>、List<JavaBean>)
	 * @param row 行索引，0~(n-1)
	 * @param key 主键
	 * @param value 默认值
	 * @return item value by key
	 */
	public static String getArrayRowStrValue(Object aryObject, int row, String key, String value){
		Object ret = getArrayRowValue(aryObject, row, key, value);

		return String.valueOf(ret);
	}

	/**
	 * 从JSON数组获取指定行某主键的整型值
	 * @param aryObject JSON数组(JSON字符串数组、JSONArray、List<Map>、List<JavaBean>)
	 * @param row 行索引，0~(n-1)
	 * @param key 主键
	 * @param value 默认值
	 * @return item value by key
	 */
	public static Integer getArrayRowIntValue(Object aryObject, int row, String key, Integer value){
		Object ret = getArrayRowValue(aryObject, row, key, value);
		try {
			return Integer.valueOf(String.valueOf(ret));
		}catch(Exception e) {
			Log4j2Tool.error(JsonTool.class, "getArrayRowIntValue:", e);
		}
		return value;
	}

	/**
	 * 从JSON数组获取指定行某主键的浮点值
	 * @param aryObject JSON数组(JSON字符串数组、JSONarray、List<Map>、List<JavaBean>)
	 * @param row 行索引，0~(n-1)
	 * @param key 主键
	 * @param value 默认值
	 * @return item value by key
	 */
	public static Float getArrayRowFloatValue(Object aryObject, int row, String key, Float value){
		Object ret = getArrayRowValue(aryObject, row, key, value);
		try {
			return Float.valueOf(String.valueOf(ret));
		}catch(Exception e) {
			Log4j2Tool.error(JsonTool.class, "getArrayRowFloatValue:", e);
		}
		return value;
	}

	/**
	 * 从JSON数组获取指定行某主键的日期值
	 * @param aryObject JSON数组(JSON字符串数组、JSONArray、List<Map>、List<JavaBean>)
	 * @param row 行索引，0~(n-1)
	 * @param key 主键
	 * @param value 默认值
	 * @return item value by key
	 */
	public static Date getArrayRowDateValue(Object aryObject, int row, String key, Date value){
		Object o = getArrayRowValue(aryObject, row, key);
		if (o==null) return value;
		if (o instanceof Date) return (Date) o;

		SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
		try{
			return format.parse(o.toString());
		}catch(ParseException e){
			Log4j2Tool.error(JsonTool.class, "getArrayRowDateValue:", e);
		}
		return value;
	}

	/**
	 * 从JSON数组获取指定行某主键的日期时间值
	 * @param aryObject JSON数组(JSON字符串数组、JSONArray、List<Map>、List<JavaBean>)
	 * @param row 行索引，0~(n-1)
	 * @param key 主键
	 * @param value 默认值
	 * @return item value by key
	 */
	public static Date getArrayRowDatetimeValue(Object aryObject, int row, String key, Date value){
		Object o = getArrayRowValue(aryObject, row, key);
		if (o==null) return value;
		if (o instanceof Date) return (Date) o;

		String time = o.toString();
		if (time.indexOf(":")<0) time += " 00:00:00";
		SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		try{
			return format.parse(time);
		}catch(ParseException e){
			Log4j2Tool.error(JsonTool.class, "getArrayRowDatetimeValue:", e);
		}
		return value;
	}

	/**
	 * 判断某个对象是否在 JSONArray 里
	 * @param jsAry JSONArray对象
	 * @param obj JSONObject
	 * @return
	 */
	private static boolean objInArray(JSONArray jsAry, Object obj){
		if ((jsAry==null) || (obj==null))
			return false;

		return jsAry.contains(obj);
	}

	/**
	 * 判断行是否在JSON数组里
	 * @param aryObject JSON数组(JSON字符串数组、JSONArray、List<Map>、List<JavaBean>)
	 * @param row JSON(JavaBean Map 或 JSON 字符串)对象
	 * @return true or false
	 */
	public static boolean rowInArray(Object aryObject, Object row){
		JSONArray ary = getJSONArray(aryObject);
		JSONObject obj= getJSONObject(row);
		return objInArray(ary, obj);
	}

	/**
	 * 往JSON数组添加行，如果行已存在，则不添加
	 * @param aryObject JSONArray
	 * @param obj JSON(JSON字符串、Map 或 JSONObject)对象
	 * @return
	 */
	private static boolean addObjToJsonArray(JSONArray aryObject, JSONObject obj){
		boolean ret = false;
		try{
			if ((aryObject==null) || (obj==null))
				return false;

			if (!objInArray(aryObject, obj)){
				aryObject.add(obj);
				ret = true;
			}
		}catch(Exception e){
			Log4j2Tool.error(JsonTool.class, "addObjToJsonArray:", e);
		}
		return ret;
	}

	/**
	 * 向JSON(JSON数组字符串、List<Map>、List<JavaBean>)数组添加行
	 * @param aryObject JSON(JSON数组字符串、JSONArray、List<Map>、List<JavaBean>)数组
	 * @param row JSON(JSONObject、JSON字符串、JavaBean、Map)行
	 * @return
	 */
	public static JSONArray addRowToArray(Object aryObject, Object row){
		JSONArray ret = getJSONArray(aryObject);
		if (ret==null) ret = new JSONArray();

		JSONObject obj = getJSONObject(row);
		addObjToJsonArray(ret, obj);
		return ret;
	}

	/**
	 * Map 转 JSON 字符串
	 * @param map Map对象
	 * @return
	 */
	public static String mapToJson(Map<String, Object> map){
		return objectToJson(map);
	}

	/**
	 * 对象转 Map
	 * @param obj JSON(JSON字符串、JSON对象、JavaBean)对象
	 * @param withoutNull 是否移除空值
	 * @return null for error bean, other return map
	 */
	@SuppressWarnings("unchecked")
	public static Map<String, Object> objectToMap(Object obj, boolean withoutNull) {
		if (obj==null) return null;
		if (obj instanceof Map) {
			Map<String, Object> map = (Map<String, Object>) obj;
			for (Map.Entry<String, Object> entry: map.entrySet()) {
				String key = entry.getKey();
				Object v = entry.getValue();
				if (withoutNull && v==null) map.remove(key);

				if (v instanceof List || v instanceof Set) map.put(key, JsonTool.getJSONArray(v));
			}

			return map;
		}

		try{
			JSONObject jo = getJSONObject(obj);
			if (jo==null) return null;

			Map<String, Object> ret = new HashMap<String, Object>();
			Set<String> keys = jo.keySet();
	        for(String key: keys){
	        	Object v = jo.get(key);
	        	if (withoutNull && v==null) continue;

	        	ret.put(key, v);
	        }
	        return ret;
		}catch(Exception e){
			Log4j2Tool.error(JsonTool.class, "objectToMap:", e);
			return null;
		}
	}	
}
